/*******************************************************************************
                      版权所有 (C), 2024-,NCUROBOT
 *******************************************************************************
  文 件 名   : referee.c 
  版 本 号   : V2.2
  作    者   : 曾伊杰
  生成日期   : 2023.5.2
 
  最近修改   : 2024.1.25
							 2024.3.2
  功能描述   : 裁判系统数据接收与解码及发送【USART初始化、UASRT中断处理、数据解码、数据发送】
							 根据2024.1发布的裁判系统串口协议V1.6版本
  函数列表   : 
*******************************************************************************/
/* 包含头文件 ----------------------------------------------------------------*/
#include "string.h"
#include "referee.h"
#include "crc.h"
#include "bsp_usart.h"
/* 内部宏定义 ----------------------------------------------------------------*/


	
/* 定义数据类型的结构体变量 --------------------------------------------------*/
Referee_robotrx__all_s  Referee_robotrx__all; 		 //存放机器人接收裁判系统数据结构体

/**注意 CMD_ID0x0301只能己方机器人通信，多机通信只能在允许的机器人间，
当接收者为选手端时（即UI绘制），只能发给对应机器人的选手端，如果需要发
送给其他机器人的选手端，需用另外一个提供的CMD_ID数据帧**/
/*******************以下均为CMD_ID为0x0301的不同数据帧********************/
/**自定图形结构体不全局定义，用在函数里静态定义，由于不同图形绘制使用的变量不同
函数省略了部分结构参数，如果共用一个会发生写入数据错误，有一些设置会在另一个图形
绘制时保留导致错误（不知道官方是如何接收的，所以认为错误）**/
sendplayer_character_s sendplayer_character;   			//绘制选手端字符串UI信息
sentry2server_cmd_s sentry2server_cmd;							//发送哨兵自主决策信息
radar2server_cmd_s	radar2server_cmd;								//发送雷达自主决策信息
robot2robot_data_s  robot2robot_data;								//发送机器人间通信数据

/*************************************************************************/
/*******************以下为与选手端小地图交互的数据帧********************/

/*雷达发送目标位置数据  雷达可通过常规链路向己方所有选手端发送对方机器人的坐标数据，
该位置会在己方选手端小地图显示。*/
radar2allplayer_target_position_s			radar2allplayer_target_position;

/*哨兵机器人或选择半自动控制方式的机器人可通过常规链路向对应的操作手选手端发送路径坐标数据，
该路径会在选手小地图上显示。*/
sentry2player_route_s					sentry2player_route;

/************************************************************************/

/*己方机器人可通过常规链路向己方任意选手端发送自定义的消息，该消息会在己方选手端特定位置显示。*/
robot2player_selected_s				robot2player_selected;



/* 内部变量 ------------------------------------------------------------------*/
uint8_t referee_rx_buf[2][REFEREE_RX_BUFFER_SIZE];//双缓冲区接收裁判系统原始数据


/* 内部函数原型声明 ----------------------------------------------------------*/
static uint16_t Determine_ID(void);
//数据处理
static void SBUS_To_Referee(uint8_t *buff, Referee_robotrx__all_s  *Referee,uint8_t rx_data_len);


/* 函数主体部分 --------------------------------------------------------------*/
/**
  * @brief				裁判系统数据接收USART初始化函数（开启DMA+开启USART空闲中断）
  * @param[in]		
	* @param[out]		
  * @retval				none
*/
void RefereeDate_Receive_USART_Init(void)
{
	USART_Init_DMA_rx (&RD_huart,&RD_DMA_USART_RX,&referee_rx_buf[0][0],REFEREE_RX_BUFFER_SIZE);
	USART_Init_DMA_tx (&RD_huart,&RD_DMA_USART_TX);
}


/**
  * @brief				裁判系统USART中断处理函数（重新设置DMA参数+数据解码+发送任务通知）
  * @param[in]		
	* @param[out]		
  * @retval				none
*/
void Referee_UART_IRQHandler(UART_HandleTypeDef *huart,DMA_HandleTypeDef *hdma_usart_rx)
{
	
	if(huart->Instance->SR & UART_FLAG_RXNE)//接收到数据
   {
     __HAL_UART_CLEAR_PEFLAG(huart);
   }
  else if(huart->Instance->SR & UART_FLAG_IDLE)		/* 判断是否为空闲中断 */
	{
	 static uint8_t referee_rx_date_len;

			/* 清除空闲标志，避免一直处于空闲状态的中断 */
			__HAL_UART_CLEAR_IDLEFLAG(huart);
		
		if ((hdma_usart_rx->Instance->CR & DMA_SxCR_CT) == RESET)
			{
				/* 关闭DMA传输 */
				__HAL_DMA_DISABLE(huart->hdmarx);

				/* 计算接收一帧裁判系统数据的长度 */
				referee_rx_date_len = (REFEREE_RX_BUFFER_SIZE - huart->hdmarx->Instance->NDTR);
			 
		
				/* 设置DMA可传输最大数据长度 */
				__HAL_DMA_SET_COUNTER(huart->hdmarx, REFEREE_RX_BUFFER_SIZE);
				//set memory buffer 1
        //设定缓冲区1
        hdma_usart_rx->Instance->CR |= DMA_SxCR_CT;
				
				/* 开启DMA传输 */
				__HAL_DMA_ENABLE(huart->hdmarx);
			 	
					/* 数据校验解码 */
				SBUS_To_Referee(referee_rx_buf[0],&Referee_robotrx__all,referee_rx_date_len);
	 
			}
		else 
		{
				/* 关闭DMA传输 */
				__HAL_DMA_DISABLE(huart->hdmarx);

				/* 计算接收一帧裁判系统数据的长度 */
				referee_rx_date_len = (REFEREE_RX_BUFFER_SIZE - huart->hdmarx->Instance->NDTR);
			 
		
				/* 设置DMA可传输最大数据长度 */
				__HAL_DMA_SET_COUNTER(huart->hdmarx, REFEREE_RX_BUFFER_SIZE);
				//set memory buffer 1
        //设定缓冲区0
        hdma_usart_rx->Instance->CR &=~(DMA_SxCR_CT);
				/* 开启DMA传输 */
				__HAL_DMA_ENABLE(huart->hdmarx);
			 
					/* 数据校验解码 */
				SBUS_To_Referee(referee_rx_buf[1],&Referee_robotrx__all,referee_rx_date_len);
		}
	}
}
/**
  * @brief				裁判系统数据解码
  * @param[in]		buff：指向数据接收数组的指针
	* @param[out]		Referee：指向存储裁判系统数据结构体的指针
  * @retval				none
*/
static void SBUS_To_Referee(uint8_t *buff, Referee_robotrx__all_s  *Referee,uint8_t rxdata_len)
{		
		uint16_t  referee_length = 0;//一帧数据总长度
		//无数据包，则不作任何处理
		if (buff == NULL)
		{
			return ;
		}
			for(uint8_t i=0;i<rxdata_len;i++)
		{
			//判断帧头数据是否为0xA5，数据长度是否正确
			if(buff[i] == FRAME_HEADER_SOF)
			{
					//写入帧头和命令码数据
				 	memcpy(Referee, buff + i, LEN_HEADER+LEN_CMDID);
					referee_length = LEN_HEADER + LEN_CMDID + Referee->frame_header.DataLength + LEN_TAIL; 
						//判断命令码进行对应数据储存
									//帧头CRC8校验及帧尾CRC16校验
					if(Verify_CRC16_Check_Sum(&buff[0+i], referee_length) && Verify_CRC8_Check_Sum(&buff[0+i],LEN_HEADER))
					{
							switch(Referee->cmdID)
							{						
									case ID_GAME_STATE:       								 //0x0001 比赛状态数据
										memcpy(&Referee->game_state, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_GAME_STATE);
									break;
									
									case ID_GAME_RESULT:      								 //0x0002 比赛结果数据
										memcpy(&Referee->game_result, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_GAME_RESULT);
									break;

									case ID_GAME_ROBOT_HP:   									 //0x0003 比赛机器人血量数据
										memcpy(&Referee->game_robot_HP, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_GAME_ROBOT_HP);
									break;				
									
									case ID_EVENT_DATA:      									 //0x0101 场地事件数据
										memcpy(&Referee->event_data, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_EVENT_DATA);
									break;	
									
									case ID_SUPPLY_PROJRCTILE_ACTION:      		 //0x0102 场地补给站动作标识数据
										memcpy(&Referee->supply_projectile_action, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_SUPPLY_PROJRCTILE_ACTION);
									break;		

									case ID_REFEREE_WARNING:      		 				 //0x0104 己方收到的裁判系统人工判罚数据，警告发生后发送
										memcpy(&Referee->referee_warning, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_REFEREE_WARNING);
									break;	

									case ID_DART_INFO:      		 		 //0x0105 飞镖数据
										memcpy(&Referee->dart_info, (buff + LEN_HEADER + LEN_CMDID + i ), LEN_DART_INFO);
									break;									
								
									case ID_GAME_ROBOT_STATUS:      		 		 	 //0x0201 机器人状态数据
										memcpy(&Referee->robot_status, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_GAME_ROBOT_STATUS);
									break;	

									case ID_POWER_HEAT_DATA:      		 		 	   //0x0202 实时功率热量数据
										memcpy(&Referee->power_heat_data, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_POWER_HEAT_DATA);
									break;

									case ID_GAME_ROBOT_POS:      		 		 	     //0x0203 机器人位置数据
										memcpy(&Referee->robot_pos, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_GAME_ROBOT_POS);
									break;

									case ID_BUFF:      		 		 	    					 //0x0204 机器人增益数据
										memcpy(&Referee->buff, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_BUFF);
									break;									
									
									case ID_AIR_SUPPORT_DATA:      		 	   //0x0205 空中机器人状态数据
										memcpy(&Referee->air_support_data, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_AIR_SUPPORT_DATA);
									break;

									case ID_HURT_DATA:      		 	  				   //0x0206 伤害状态数据
										memcpy(&Referee->hurt_data, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_HURT_DATA);
									break;

									case ID_SHOOT_DATE:      		 	  				   //0x0207 实时射击数据
										memcpy(&Referee->shoot_data, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_SHOOT_DATE);
									break;	

									case ID_PROJECTILE_ALLOWANCE:      		 	  //0x0208 允许发弹量相关数据，对地面机器人和空中机器人发送
										memcpy(&Referee->projectile_allowance, (buff + LEN_HEADER + LEN_CMDID + i ), LEN_PROJECTILE_ALLOWANCE);
									break;	

									case ID_RFID_STATUS:      		 	  		 		 //0x0209 机器人 RFID 状态
										memcpy(&Referee->RFID_status, (buff + LEN_HEADER + LEN_CMDID+ i  ), LEN_RFID_STATUS);
									break;

									case ID_DART_CLIENT_CMD:      		 	  		 //0x20A 飞镖机器人客户端指令数据
										memcpy(&Referee->dart_client_cmd, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_DART_CLIENT_CMD);
									break;
									
									case ID_GROUND_ROBOT_POSITION_DATA	:      		 	  //0x020B,地面机器人位置数据，对哨兵机器人发送
										memcpy(&Referee-> ground_robot_position, (buff + LEN_HEADER + LEN_CMDID+ i ), LEN_GROUND_ROBOT_POSITION_DATA);
									break;
		
									case ID_RADAR_MARK_DATA	:      		 	         //0x020C,雷达标记进度数据，向雷达发送，以 1Hz 频率发送
										memcpy(&Referee-> radar_mark_data, (buff + LEN_HEADER + LEN_CMDID+ i ),LEN_RADAR_MARK_DATA);
									break;
									
									case ID_MAP_COMMAND:                         //0x0302,自定义控制器与机器人交互数据，发送方触发发送，频率上限为30Hz
										memcpy(&Referee->map_command,(buff + LEN_HEADER + LEN_CMDID+ i ), LEN_MAP_COMMAND);
									break;
									
									case ID_CUSTOM_ROBOT_DATA:                         //0x0303,客户端下发信息（小地图下发）
										memcpy(&Referee->map_command,(buff + LEN_HEADER + LEN_CMDID+ i ), LEN_CUSTOM_ROBOT_DATA);
									break;
									
									case ID_REMOTE_CONTROL:          //0x304, 键盘、鼠标信息，通过图传串口发送
									 memcpy(&Referee->remote_contrl,(buff + LEN_HEADER + LEN_CMDID+ i ), LEN_REMOTE_CONTROL);
									break;									   									
							}	
					i=i+referee_length;								
					 }

	   }
	 }			
}

/**
	* @brief  判断自身ID，选择客户端ID(用于UI发送)
  * @param  void
  * @retval RED   BLUE
  */
static uint16_t Determine_ID(void)
{
	 uint16_t Referee_SelfClient_ID=0;
	if(Referee_robotrx__all.robot_status.robot_id>=1&&Referee_robotrx__all.robot_status.robot_id<=6)
	{
		Referee_SelfClient_ID=0x0100+Referee_robotrx__all.robot_status.robot_id;
	}
	else if(Referee_robotrx__all.robot_status.robot_id>=101&&Referee_robotrx__all.robot_status.robot_id<=106)
	{
		Referee_SelfClient_ID=0x0164+(Referee_robotrx__all.robot_status.robot_id-100);
	}
	
		return Referee_SelfClient_ID;
}

/**
  * @brief  自定义图形，画直线或者矩形或者椭圆
  * @param[in]	图形的名称name 图形操作operate 图形的类型 type  图层 （0~9）图形的颜色color 图形的宽度 width  
								起点坐标（s_x,s_y）  (e_x e_y不同图形作用不同)
																			直线：终点坐标
																			矩形：对角顶点坐标
																			椭圆：半轴长度
	* @param[out]		
  * @retval				none
*/
void DrawLine_Rectangle_Ellipse(uint32_t name,Operate_e operate_tpye,Type_e figure_tpye,uint32_t layer,Color_e color,uint32_t width ,uint32_t s_x,uint32_t s_y,uint32_t e_x,uint32_t e_y)                
{
	static sendplayer_figure1_s sendplayer_figure1;
	//写入帧头数据
	sendplayer_figure1.FrameHeader.SOF					=FRAME_HEADER_SOF;
	sendplayer_figure1.FrameHeader.DataLength		=sizeof(sendplayer_figure1_s)-9;
	sendplayer_figure1.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1.FrameHeader));
	//写入对应命令码
	sendplayer_figure1.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	sendplayer_figure1.robot_interaction_data.data_cmd_id	=GRAPHICS1_CMD_ID; //设置为画一个图形
	sendplayer_figure1.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	sendplayer_figure1.robot_interaction_data.receiver_id	=Determine_ID();
	//设置图形数据
	sendplayer_figure1.interaction_figure.figure_name[0]=(uint8_t) name;
	sendplayer_figure1.interaction_figure.figure_name[1]=(uint8_t) name >>8;
	sendplayer_figure1.interaction_figure.figure_name[2]=(uint8_t) name >>16;
	
	sendplayer_figure1.interaction_figure.operate_tpye	=operate_tpye;
	sendplayer_figure1.interaction_figure.figure_tpye		=figure_tpye;
	sendplayer_figure1.interaction_figure.layer					=layer;
	sendplayer_figure1.interaction_figure.color					=color;
	sendplayer_figure1.interaction_figure.width					=width;
	sendplayer_figure1.interaction_figure.start_x				=s_x;
	sendplayer_figure1.interaction_figure.start_y				=s_y;
	sendplayer_figure1.interaction_figure.details_d			=e_x;
	sendplayer_figure1.interaction_figure.details_e			=e_y;
	//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
}


/**
  * @brief  自定义图形，画整圆
  * @param[in]	图形的名称name 图形操作operate 图形的类型 type  图层 （0~9）图形的颜色color 图形的宽度 width  
								起点坐标（s_x,s_y）  (e_x e_y不同图形作用不同)
																			直线：终点坐标
																			矩形：对角顶点坐标
																			椭圆：半轴长度
	* @param[out]		
  * @retval				none
*/
void DrawFullCircle(uint32_t name,Operate_e operate_tpye,Type_e figure_tpye,uint32_t layer,Color_e color,uint32_t width ,uint32_t s_x,uint32_t s_y,uint32_t radius)                
{
	static sendplayer_figure1_s sendplayer_figure1;
	//写入帧头数据
	sendplayer_figure1.FrameHeader.SOF					=FRAME_HEADER_SOF;
	sendplayer_figure1.FrameHeader.DataLength		=(sizeof(sendplayer_figure1_s)-9);
	sendplayer_figure1.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1.FrameHeader));
	//写入对应命令码
	sendplayer_figure1.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	sendplayer_figure1.robot_interaction_data.data_cmd_id	=GRAPHICS1_CMD_ID; //设置为画一个图形
	sendplayer_figure1.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	sendplayer_figure1.robot_interaction_data.receiver_id	=Determine_ID();
	//设置图形数据
	sendplayer_figure1.interaction_figure.figure_name[0]=(uint8_t) name;
	sendplayer_figure1.interaction_figure.figure_name[1]=(uint8_t) name >>8;
	sendplayer_figure1.interaction_figure.figure_name[2]=(uint8_t) name >>16;
	sendplayer_figure1.interaction_figure.operate_tpye	=operate_tpye;
	sendplayer_figure1.interaction_figure.figure_tpye		=figure_tpye;
	sendplayer_figure1.interaction_figure.layer					=layer;
	sendplayer_figure1.interaction_figure.color					=color;
	sendplayer_figure1.interaction_figure.width					=width;
	sendplayer_figure1.interaction_figure.start_x				=s_x;
	sendplayer_figure1.interaction_figure.start_y				=s_y;
	sendplayer_figure1.interaction_figure.details_c			=radius;
	//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
	
	HAL_UART_Transmit_DMA(&RD_huart ,(uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
}





/**
  * @brief  自定义图形，画圆弧
  * @param[in]	图形的名称name 图形操作operate 图形的类型 type  图层 （0~9）图形的颜色color 图形的宽度 width  
								起点坐标（s_x,s_y）  起始和终止角度（s_angle e_angle）半长轴长度（e_x e_y）
								角度值含义为：0°指 12 点钟方向，顺时针绘制；
	* @param[out]		
  * @retval				none
*/
void DrawARC(uint32_t name,Operate_e operate_tpye,Type_e figure_tpye,uint32_t layer,Color_e color,uint32_t width ,uint32_t s_angle,uint32_t e_angle,uint32_t s_x,uint32_t s_y,uint32_t e_x,uint32_t e_y)                
{
	static sendplayer_figure1_s sendplayer_figure1;
	//写入帧头数据
	sendplayer_figure1.FrameHeader.SOF					=FRAME_HEADER_SOF;
	sendplayer_figure1.FrameHeader.DataLength		=sizeof(sendplayer_figure1_s)-9;
	sendplayer_figure1.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1.FrameHeader));
	//写入对应命令码
	sendplayer_figure1.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	sendplayer_figure1.robot_interaction_data.data_cmd_id	=GRAPHICS1_CMD_ID; //设置为画一个图形
	sendplayer_figure1.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	sendplayer_figure1.robot_interaction_data.receiver_id	=Determine_ID();
	//设置图形数据
	sendplayer_figure1.interaction_figure.figure_name[0]=(uint8_t) name;
	sendplayer_figure1.interaction_figure.figure_name[1]=(uint8_t) name >>8;
	sendplayer_figure1.interaction_figure.figure_name[2]=(uint8_t) name >>16;
	sendplayer_figure1.interaction_figure.operate_tpye	=operate_tpye;
	sendplayer_figure1.interaction_figure.figure_tpye		=figure_tpye;
	sendplayer_figure1.interaction_figure.layer					=layer;
	sendplayer_figure1.interaction_figure.color					=color;
	sendplayer_figure1.interaction_figure.width					=width;
	sendplayer_figure1.interaction_figure.start_x				=s_x;
	sendplayer_figure1.interaction_figure.start_y				=s_y;
	sendplayer_figure1.interaction_figure.details_a			=s_angle;
	sendplayer_figure1.interaction_figure.details_b			=e_angle;
	sendplayer_figure1.interaction_figure.details_d			=e_x;
	sendplayer_figure1.interaction_figure.details_e			=e_y;
		//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
}


/**
  * @brief  自定义图形，绘制整型数 和 浮点数
  * @param[in]	图形的名称name 图形操作operate 图形的类型 type  图层 （0~9）图形的颜色color 图形的宽度 width  
								起点坐标（s_x,s_y）  整形数Integral  浮点数 Float(当绘制浮点数时，显示的值是整形数/1000  1245->1.245)

	* @param[out]		
  * @retval				none
*/
void DrawIntegral_Float(uint32_t name,Operate_e operate_tpye,Type_e figure_tpye,uint32_t layer,Color_e color,uint32_t width,uint32_t Font_size,uint32_t s_x,uint32_t s_y,int32_t count_type)                
{
	static sendplayer_figure1_s sendplayer_figure1;
	//写入帧头数据
	sendplayer_figure1.FrameHeader.SOF					=FRAME_HEADER_SOF;
	sendplayer_figure1.FrameHeader.DataLength		=sizeof(sendplayer_figure1_s)-9;
	sendplayer_figure1.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1.FrameHeader));
	//写入对应命令码
	sendplayer_figure1.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	sendplayer_figure1.robot_interaction_data.data_cmd_id	=GRAPHICS1_CMD_ID; //设置为画一个图形
	sendplayer_figure1.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	sendplayer_figure1.robot_interaction_data.receiver_id	=Determine_ID();
	//设置图形数据
	sendplayer_figure1.interaction_figure.figure_name[0]=(uint8_t) name;
	sendplayer_figure1.interaction_figure.figure_name[1]=(uint8_t) name >>8;
	sendplayer_figure1.interaction_figure.figure_name[2]=(uint8_t) name >>16;
	sendplayer_figure1.interaction_figure.operate_tpye	=operate_tpye;
	sendplayer_figure1.interaction_figure.figure_tpye		=figure_tpye;
	sendplayer_figure1.interaction_figure.layer					=layer;
	sendplayer_figure1.interaction_figure.color					=color;
	sendplayer_figure1.interaction_figure.width					=width;
	sendplayer_figure1.interaction_figure.start_x				=s_x;
	sendplayer_figure1.interaction_figure.start_y				=s_y;
	sendplayer_figure1.interaction_figure.details_a			=Font_size;
	sendplayer_figure1.interaction_figure.details_c			=count_type;
	sendplayer_figure1.interaction_figure.details_d			=count_type >> 10;
	sendplayer_figure1.interaction_figure.details_e			=count_type >> 21;
		//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&sendplayer_figure1,sizeof(sendplayer_figure1_s));
}




/*整形数转字符串，可将整形数据转换为字符串数据发送
也可使用sprintf格式化字符串数据进行发送*/

char* itoa(int num,char* str,int radix)
{
	char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//索引表
	unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数
	int i=0,j,k;//i用来指示设置字符串相应位，转换之后i其实就是字符串的长度；转换后顺序是逆序的，有正负的情况，k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。
 
	//获取要转换的整数的绝对值
	if(radix==10&&num<0)//要转换成十进制数并且是负数
	{
		unum=(unsigned)-num;//将num的绝对值赋给unum
		str[i++]='-';//在字符串最前面设置为'-'号，并且索引加1
	}
	else unum=(unsigned)num;//若是num为正，直接赋值给unum
 
	//转换部分，注意转换后是逆序的
	do
	{
		str[i++]=index[unum%(unsigned)radix];//取unum的最后一位，并设置为str对应位，指示索引加1
		unum/=radix;//unum去掉最后一位
        if(i > 29)
            return NULL;
	}while(unum);//直至unum为0退出循环
 
	str[i]='\0';//在字符串最后添加'\0'字符，c语言字符串以'\0'结束。
 
	//将顺序调整过来
	if(str[0]=='-') k=1;//如果是负数，符号不用调整，从符号后面开始调整
	else k=0;//不是负数，全部都要调整
 
	char temp;//临时变量，交换两个值时用到
	for(j=k;j<=(i-1)/2;j++)//头尾一一对称交换，i其实就是字符串的长度，索引最大值比长度少1
	{
		temp=str[j];//头部赋值给临时变量
		str[j]=str[i-1+k-j];//尾部赋值给头部
		str[i-1+k-j]=temp;//将临时变量的值(其实就是之前的头部值)赋给尾部
	}
 
	return str;//返回转换后的字符串
}


/**
  * @brief  自定义图形，绘制字符串
  * @param[in]	图形的名称name 图形操作operate 图形的类型 type  图层 （0~9）图形的颜色color 图形的宽度 width  
								起点坐标（s_x,s_y）  字体大小 character_size   字符长度character_len 字符数组char string[30]

	* @param[out]		
  * @retval				none
*/
void DrawString(uint32_t name,Operate_e operate_tpye,Type_e figure_tpye,uint32_t layer,Color_e color,uint32_t width,uint32_t character_size,uint32_t character_len,uint32_t s_x,uint32_t s_y,char string[30])                
{
	//写入帧头数据
	sendplayer_character.FrameHeader.SOF					=FRAME_HEADER_SOF;
	sendplayer_character.FrameHeader.DataLength		=sizeof(sendplayer_character)-9;
	sendplayer_character.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&sendplayer_character,sizeof(sendplayer_character.FrameHeader));
	//写入对应命令码
	sendplayer_character.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	sendplayer_character.robot_interaction_data.data_cmd_id	=CHARACTER_CMD_ID; //设置字符串
	sendplayer_character.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	sendplayer_character.robot_interaction_data.receiver_id	=Determine_ID();
	//设置图形数据
	sendplayer_character.client_custom_character.interaction_figure.figure_name[0]=(uint8_t) name;
	sendplayer_character.client_custom_character.interaction_figure.figure_name[1]=(uint8_t) name >>8;
	sendplayer_character.client_custom_character.interaction_figure.figure_name[2]=(uint8_t) name >>16;
	sendplayer_character.client_custom_character.interaction_figure.operate_tpye	=operate_tpye;
	sendplayer_character.client_custom_character.interaction_figure.figure_tpye		=figure_tpye;
	sendplayer_character.client_custom_character.interaction_figure.layer					=layer;
	sendplayer_character.client_custom_character.interaction_figure.color					=color;
	sendplayer_character.client_custom_character.interaction_figure.width					=width;
	sendplayer_character.client_custom_character.interaction_figure.start_x				=s_x;
	sendplayer_character.client_custom_character.interaction_figure.start_y				=s_y;
	sendplayer_character.client_custom_character.interaction_figure.details_a			=character_size;
	sendplayer_character.client_custom_character.interaction_figure.details_b			=character_len;
	
	
	strcpy((char *)sendplayer_character.client_custom_character.data,string);
		//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&sendplayer_character,sizeof(sendplayer_character));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&sendplayer_character,sizeof(sendplayer_character));
}



/**
  * @brief  发送哨兵自主决策信息
  * @param[in]	reborn ：是否立即复活 0：不复活（即使计时结束） 1：计时后就立即复活  exchange_reborn：是否金兵兑换复活 0：不对换 1：兑换
								exchange_Bullet_volume ：兑换发弹量开局为 0，修改此值后，哨兵在补血点即可兑换允许发弹量，此值的变化需要单调递增，否则视为不合法。
								remote_Bullet_volume_times：哨兵远程兑换发弹量的请求次数，开局为 0，修改此值即可请求远程兑换发弹量。此值的变化需要单调递增且每次仅能增加 1，否则视为不合法。
								remote_Blood_volume_times：哨兵远程兑换血量的请求次数，开局为 0，修改此值即可请求远程兑换血量。此值的变化需要单调递增且每次仅能增加 1，否则视为不合法
								bit 21-31：保留
  * @param[out]		
  * @retval				none
*/
void Sendsentry_auto_cmd(bool_t reborn,bool_t remote_reborn,uint16_t exchange_Bullet_amount,uint8_t remote_Bullet_volume_times,uint8_t remote_Blood_volume_times)                
{
	//写入帧头数据
	sentry2server_cmd.FrameHeader.SOF					=FRAME_HEADER_SOF;
	sentry2server_cmd.FrameHeader.DataLength		=sizeof(sentry2server_cmd_s)-9;
	sentry2server_cmd.FrameHeader.Seq					=0;
  	Append_CRC8_Check_Sum((uint8_t *)&sentry2server_cmd,sizeof(sentry2server_cmd.FrameHeader));
	//写入对应命令码
	sentry2server_cmd.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	sentry2server_cmd.robot_interaction_data.data_cmd_id	=SENTRY_CMD_ID; //设置内容ID
	sentry2server_cmd.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	sentry2server_cmd.robot_interaction_data.receiver_id	=0x8080;//发送至服务器
	

	sentry2server_cmd.sentry_cmd_data.is_resurrection=reborn;
	sentry2server_cmd.sentry_cmd_data.is_resurrection_remote=remote_reborn;
	sentry2server_cmd.sentry_cmd_data.allow_bill_amount=exchange_Bullet_amount;
  	sentry2server_cmd.sentry_cmd_data.allow_bill_times_remote=remote_Bullet_volume_times;
	sentry2server_cmd.sentry_cmd_data.blood_remote_times=remote_Blood_volume_times;
		//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&sentry2server_cmd,sizeof(sentry2server_cmd_s));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&sentry2server_cmd,sizeof(sentry2server_cmd_s));
}


/**
  * @brief  发送雷达自主决策信息
* @param[in]	trigger_choose:开局为 0，修改此值即可请求触发双倍易伤，若此时雷达拥有触发双倍易伤的机会，则可触发。
								此值的变化需要单调递增且每次仅能增加 1，否则视为不合法。
								
	* @param[out]		
  * @retval				none
*/
void Sendradar_auto_cmd(uint8_t trigger_choose)                
{
	//写入帧头数据
	radar2server_cmd.FrameHeader.SOF					=FRAME_HEADER_SOF;
	radar2server_cmd.FrameHeader.DataLength		=sizeof(radar2server_cmd_s)-9;
	radar2server_cmd.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&radar2server_cmd,sizeof(radar2server_cmd.FrameHeader));
	//写入对应命令码
	radar2server_cmd.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	radar2server_cmd.robot_interaction_data.data_cmd_id	=RADAR_CMD_ID; //设置内容ID
	radar2server_cmd.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	radar2server_cmd.robot_interaction_data.receiver_id	=0x8080;//发送至服务器
	

	radar2server_cmd.radar_cmd_data.radar_cmd			=	trigger_choose;
	
	Append_CRC16_Check_Sum((uint8_t *)&radar2server_cmd,sizeof(radar2server_cmd_s));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&radar2server_cmd,sizeof(radar2server_cmd_s));
}




/**
  * @brief  发送机器人之间通信数据只能够在允许多机通信的机器人间法发送
  * @param[in]	interaction_data：要传输的数据 

	* @param[out]		
  * @retval				none
*/
void Sendrobotinteract_message(uint8_t *interaction_data)
{
	//写入帧头数据
	robot2robot_data.FrameHeader.SOF					=FRAME_HEADER_SOF;
	robot2robot_data.FrameHeader.DataLength		=sizeof(robot2robot_data)-9;
	robot2robot_data.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&robot2robot_data,sizeof(robot2robot_data.FrameHeader));
	//写入对应命令码
	robot2robot_data.CmdID		= ID_ROBOT_INTERACTION_DATA;
	//设置内容数据头
	robot2robot_data.robot_interaction_data.data_cmd_id	=INTERACTION_ID1; //设置内容ID
	robot2robot_data.robot_interaction_data.sender_id	 	=Referee_robotrx__all.robot_status.robot_id;
	robot2robot_data.robot_interaction_data.receiver_id	=0x8080;//发送至服务器
	
	memcpy(robot2robot_data.user_data,interaction_data,sizeof(robot2robot_data.user_data));
	//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&robot2robot_data,sizeof(robot2robot_data));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&robot2robot_data,sizeof(robot2robot_data));
}



/******************以下为除CMD_ID为0x301的其他ID发送的消息*******************/

/**
  * @brief 雷达可通过常规链路向己方所有选手端发送对方机器人的坐标数据，该位置会在己方选手端小地图显示
	* @param[in]	target_id: 目标机器人ID  target_x target_y :目标机器人位置

	* @param[out]		
  * @retval				none
*/
void RadarSendtargetPosition(uint16_t target_id,float target_x, float target_y)
{
	//写入帧头数据
	radar2allplayer_target_position.FrameHeader.SOF					=FRAME_HEADER_SOF;
	radar2allplayer_target_position.FrameHeader.DataLength		=sizeof(radar2allplayer_target_position)-9;
	radar2allplayer_target_position.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&radar2allplayer_target_position,sizeof(radar2allplayer_target_position.FrameHeader));
	//写入对应命令码
	radar2allplayer_target_position.CmdID		= ID_MAD_ROBOT_DATA;
	//设置数据
	radar2allplayer_target_position.map_robot_data.target_robot_id	=target_id;
	radar2allplayer_target_position.map_robot_data.target_position_x=target_x;
	radar2allplayer_target_position.map_robot_data.target_position_y=target_y;
	
	//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&radar2allplayer_target_position,sizeof(radar2allplayer_target_position));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&radar2allplayer_target_position,sizeof(radar2allplayer_target_position));
}


/**
  * @brief  哨兵机器人或选择半自动控制方式的机器人可通过常规链路向对应的操作手选手端发送路径坐标数据，该路径会在小地图上显示。
* @param[in]	behavior: 1：到目标点攻击	2：到目标点防守	3：移动到目标点

	* @param[out]		
  * @retval				none
*/
void SentrySendSelfroute(uint8_t behavior,uint16_t s_x ,uint16_t s_y,int8_t delta_x[49],int8_t delta_y[49])
{
	//写入帧头数据
	sentry2player_route.FrameHeader.SOF					=FRAME_HEADER_SOF;
	sentry2player_route.FrameHeader.DataLength		=sizeof(sentry2player_route)-9;
	sentry2player_route.FrameHeader.Seq					=0;
  Append_CRC8_Check_Sum((uint8_t *)&sentry2player_route,sizeof(sentry2player_route.FrameHeader));
	//写入对应命令码
	sentry2player_route.CmdID		= ID_MAD_DATA;
	//设置数据
	sentry2player_route.map_data.intention 				=behavior;
	sentry2player_route.map_data.start_position_x	=s_x;
	sentry2player_route.map_data.start_position_y	=s_y;
  memcpy(sentry2player_route.map_data.delta_x,delta_x,49);
	memcpy(sentry2player_route.map_data.delta_y,delta_y,49);
	
	sentry2player_route.map_data.sender_id				=Referee_robotrx__all.robot_status.robot_id;
	//加入帧尾CRC16校验
	Append_CRC16_Check_Sum((uint8_t *)&sentry2player_route,sizeof(sentry2player_route));
	
	HAL_UART_Transmit_DMA(&RD_huart,(uint8_t *)&sentry2player_route,sizeof(sentry2player_route));
}



/**
  * @brief  选手端小地图接收机器人数据（0x308 待加入目前用不到）
* @param[in]	

	* @param[out]		
  * @retval				none
*/



